/* Object representing a player of the game.
 * @param gameboard reference back to the gameboard this is a part of.
 * @param target the UI element that this player represents.
 * @param fills an array of the peices this drops when moving off spaces.
 */
function Player(gameboard, target, fills) {
	this.gameboard = gameboard;
	this.target = target;
	this.fills = fills;
	
	++this.gameboard.movingPlayers;
}

Player.prototype.isActivated = false;
Player.prototype.isAutoPlayer = false;
Player.prototype.score = 0;
Player.prototype.canMove = true;
Player.prototype.totalAnimationSteps = 0;

/* Add some points to the score of this char */
Player.prototype.addScore = function(value) {
	this.score += value;
	// Calls back to the gameboard.
	this.scoreCallback(value);
}

/* Place the player over the specified tile
 * @param x,y the coordinates of the tile to move to.
 */
Player.prototype.setPosition = function(x, y) {
	this.x = x;
	this.y = y;
	
	if (y % 2 == 0)
		this.target["Canvas.Left"] = x * 96;
	else
		this.target["Canvas.Left"] = x * 96 + 50;
		
	// Account for the height of the tile
	var hex = this.getCurrentHex();
	var height = hex.value - 1;
	height *= 12;
		
	this.target["Canvas.Top"] = y * 76 - height + 20;
	
	hex.occupier = this;
}

/* Animates the player to the specified tile (as opposed to just moving it to there)
 * @param x,y the coordinates of the tile to move to.
 */
Player.prototype.animatePlayerTo = function(x, y) {
	this.x = x;
	this.y = y;
	
	var finalX = x * 96;
	if (y % 2 == 1)
		finalX += 50;
	
		
	var hex = this.getCurrentHex();
	var height = hex.value - 1;
	height *= 12;
	
	var finalY = y * 76 - height + 20;
	
	this.animateTo(finalX, finalY);
	
	hex.occupier = this;
}

/* Get the hex this is currently over. */
Player.prototype.getCurrentHex = function() {
	return this.gameboard.hexes[this.x][this.y];
}

/* Make this player the active player. 
 * If this player is a computer-controlled player, then this will run the
 * strategy to find the next move, then take it.
 */
Player.prototype.activate = function() {
	if (!this.isActivated) {
		// Show the marker that this is the active player
		var marker = this.gameboard.control.createFromXaml(this.gameboard.markerXaml);
		var hex = this.getCurrentHex();
		
		hex.target.Children.Add(marker);
		
		marker["Canvas.Top"] = (hex.value - 1) * -12;
		
		this.isActivated = true;
		
		// Run the logic to auto play if needed.
		if (this.isAutoPlayer)
			this.autoPlay();
		// Check if this player can actually move, if not, lose.
		else if (this.dumbFindBestPlay() == null) {
			this.setOverDeveloped();
			this.gameboard.nextPlayer();
		}
	}
}

/* Called when this players turn is over. */
Player.prototype.deactivate = function() {
	if (this.isActivated) {	
		var hex = this.getCurrentHex();
		hex.target.children.removeAt(hex.target.children.count - 1);
		
		this.isActivated = false;
		
		hex.setFill(this.fills[hex.value - 1]);
	}
}

/* Runs all the logic needed to find the next move.
 * Used for the computer controlled players.
 */
Player.prototype.autoPlay = function() {
	if (!this.canMove) {
		this.gameboard.nextPlayer();
		return;
	}
	
	var currentHex = this.getCurrentHex();
	var topHex = this.findBestPlay();

	if (topHex != null)
		this.gameboard.tryMoveTo(topHex);
	else {
		this.setOverDeveloped();
		this.gameboard.nextPlayer();
	}
}

/* Oh noes! we ran out of room!
 * Called when the player can no longer move.
 */
Player.prototype.setOverDeveloped = function() {
	if (this.canMove) {
		this.canMove = false;
		this.gameboard.decrementMovingPlayers();
		if (this.isAutoPlayer)
			this.target.Opacity = 0;
	}
}

/* Find the next best play, this is the standard Suit strategy.
 */
Player.prototype.dynamicFindBestPlay = function() {
	var maxRadius = 10;
	var depth = 2;
	
	if (this.gameboard.openSpaces < 70) {
		maxRadius = 7;
		depth = 1;
	}
	if (this.gameboard.openSpaces < 65) {
		depth = 2;
		maxRadius = 5;
	}
	if (this.gameboard.openSpaces < 50) {
		depth = 2;
		maxRadius = 5;
	}
	
	return this.getBestPlay(maxRadius, depth);
}

/* Find the next best play using more logic, but looking less distance.
 * This is the default Techy strategy.
 */
Player.prototype.timidFindBestPlay = function() {
	var maxRadius = 3;
	var depth = 2;
	
	return this.getBestPlay(maxRadius, depth);
}

Player.prototype.dumbFindBestPlay = function() {
	var maxRadius = 1;
	var depth = 0;
	
	return this.getBestPlay(maxRadius, depth);
}

// Default player strategy to the dynamic version.
Player.prototype.findBestPlay = Player.prototype.dynamicFindBestPlay;

/* Find the best play, using a really really really bad algorithm.
 * This algorithm is here until Janete implements her uber min/max algorithm for me,
 * but it was able to beat her 3 times in a row :)
 * @param maxRadius max distance to look for a good spot.
 * @param depth amount of look ahead to use when considering what a good spot is.
 */
Player.prototype.getBestPlay = function(maxRadius, depth) {
	var topHex = null;
	var currentHex = this.getCurrentHex();
	var topFullValue = -1;
	var topValue = -1;
	var player = this;
	
	var playFinder = function(hex) {
		if (player.gameboard.canMoveTo(hex, player, currentHex)) {
			var value = Math.pow(hex.value, depth + 1);
			if (depth > 0)
				value = player.findHexValue(hex, maxRadius, depth - 1);
				
			if (value >= topFullValue) {
				topFullValue = value;
				topValue = hex.value;
				topHex = hex;
			}
			return true;
		}
		return false;
	}
	
	this.gameboard.walkPossibilities(currentHex, maxRadius, playFinder);
	
	return topHex;
}

/* Uses lame logic to determine how good a specific hex is to move to.
 * Takes into consideration the value of the hexes around this one.
 */
Player.prototype.findHexValue = function(base, maxRadius, depth) {
	var value = base.value;
	var player = this;
	
	var valueFinder = function(hex) {
		if (player.gameboard.canMoveTo(hex, player, base)) {
			value += hex.value;
			if (depth > 1) {
				value += player.findHexValue(hex, maxRadius, depth - 1);
			}
			return true;
		}
		return false;
	}
	
	this.gameboard.walkPossibilities(base, maxRadius, valueFinder);
	
	return value;
}

/* Per frame callback when animating this character to another tile. */
Player.prototype.handleAnimationUpdate = function() {
	++this.animationStep;
	if (this.animationStep <= this.totalAnimationSteps) {
	
		var delta = this.animationStep / this.totalAnimationSteps;
		this.target["Canvas.Left"] = (this.destinationX - this.startX) * delta + this.startX;
		this.target["Canvas.Top"] = (this.destinationY - this.startY) * delta + this.startY;
	}
		
	if (this.animationStep > this.totalAnimationSteps + 1)
		this.stopAnimation();
}

/* Starts the animation to the specific position on the board.
 * @param x,y coordinates (in pts) of where to move to.
 */
Player.prototype.animateTo = function(x, y) {
	this.startX = this.target["Canvas.Left"];
	this.startY = this.target["Canvas.Top"];
	this.destinationX = x;
	this.destinationY = y;
	
	var deltaX = this.destinationX - this.startX;
	var deltaY = this.destinationY - this.startY;
	var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
	var totalSteps = Math.round(distance / 10);
	this.totalAnimationSteps = totalSteps;
	this.animationStep = 0;
	
	this.gameboard.startAnimation(this);
}

/* Stop this character from moving. */
Player.prototype.stopAnimation = function() {
	this.animationStep = 0;
	this.totalAnimationSteps = 0;
	
	this.gameboard.stopAnimation(this);
	this.gameboard.nextPlayer();
}

/* Checks to see if this character is animating,
 * used to prevent certain actions after the next play choice has been
 * committed, but the player has not changed.
 */
Player.prototype.isAnimating = function() {
	return this.totalAnimationSteps != 0;
}